﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using UnityEngine;
using Warensoft.Unity.Communication.Client.Models;

namespace Warensoft.Unity.Communication.Client.OData
{
    public class ODataContext
    {
        private string url;
        private string baseUrl;

        private HttpClient httpClient;
        private Dictionary<string, ODataTable> tables=new Dictionary<string,ODataTable> ();

        public Dictionary<string, ODataTable> Tables
        {
            get { return tables; }
            set { tables = value; }
        }
        public bool SchemaLoaded { get; set; }
        public event EventHandler SchemaLoadCompleted;
        public ODataContext(string url)
        {
            this.SchemaLoaded = false;
            this.url = url;
            this.httpClient = CommunicationManager.CreateInstance ().GetHttpClient();
            string meta = this.url + "/$metadata";
            MonoBehaviour.print("begin get meta:"+meta);
            this.httpClient.BeginGetHttpContent(meta, new Action<XmlDocument>((result) =>
            {
                var entityNodes = result.DocumentElement.ChildNodes[0].ChildNodes[0].ChildNodes.Cast<XmlNode>().Where(node => node.Name == "EntityType");
                foreach (var node in entityNodes)
                {
                    
                    var properties = node.ChildNodes.Cast<XmlNode>().Where(p => p.Name == "Property").Select(p => new ODataProperty()
                                    {
                                        Name = p.Attributes["Name"].Value,
                                        DataType = GetEdmType(p.Attributes["Type"].Value),
                                        IsNullable = bool.Parse(p.Attributes["Nullable"].Value),
                                        IsPremaryKey =false 
                                    }
                                    ).ToList();
                    var pkFields = node.ChildNodes.Cast<XmlNode>().Where(p => p.Name == "Key");
                    
                    if (pkFields .Count ()!=0)
                    {
                        foreach (XmlNode keyNode in pkFields.First ().ChildNodes )
                        {
                            var pkFieldName = keyNode.Attributes["Name"].Value;
                            properties.First(p => p.Name == pkFieldName).IsPremaryKey = true;
                        }
                        
                    }
                    var navigations = node.ChildNodes.Cast<XmlNode>().Where(p => p.Name == "NavigationProperty").Select(p => new ODataNavigation() { Name =p.Attributes["Name"].Value  }).ToList ();
                    ODataTable table = new ODataTable(node.Attributes["Name"].Value, this.url + "/" + node.Attributes["Name"].Value,false , properties,navigations,this);
                    MonoBehaviour.print(node.Attributes["Name"].Value);
                    this.tables.Add(table.TableName,table);
                   
                }
                MonoBehaviour.print("load finished");
                 this.SchemaLoaded = true;
                    if (this.SchemaLoadCompleted!=null )
                    {
                        this.SchemaLoadCompleted(this,new EventArgs ());
                    }
            }));
        }

        private Type GetEdmType(string typeString)
        {
            Type result = typeof(object);

            switch (typeString)
            {
                case "Edm.Boolean":
                    result = typeof(bool);
                    break;
                case "Edm.Byte":
                    result = typeof(byte);
                    break;
                case "Edm.DateTime":
                    result = typeof(DateTime );
                    break;
                case "Edm.Decimal":
                    result = typeof(decimal);
                    break;
                case "Edm.Double":
                    result = typeof(double );
                    break;
                case "Edm.Single":
                    result = typeof(float);
                    break;
                case "Edm.Guid":
                    result = typeof(Guid);
                    break;
                case "Edm.Int16":
                    result = typeof(short);
                    break;
                case "Edm.Int32":
                    result = typeof(int);
                    break;
                case "Edm.Int64":
                    result = typeof(long);
                    break;
                case "Edm.SByte":
                    result = typeof(bool);
                    break;
                case "Edm.String":
                    result = typeof(sbyte);
                    break;
                case "Edm.Time":
                    result = typeof(object);
                    break;
                case "Edm.DateTimeOffset":
                    result = typeof(object);
                    break;
                default:
                    break;
            }
            return result;
        }
       
    }
}
